﻿$sc = function () {
    var $d = document;
    var ie = $d.all ? true : false;
    // extension on date object
    Date.p = Date.prototype;
    Date.p.y = Date.p.getFullYear;
    Date.p.n = Date.p.getMonth;
    Date.p.m = function () { return this.n() + 1; }
    Date.p.d = Date.p.getDate;
    Date.p.h = Date.p.getHours;
    Date.p.i = Date.p.getMinutes;
    Date.p.s = Date.p.getSeconds;
    Date.p.fs = function (f) {
        String.prototype.r = String.prototype.replace;
        Number.prototype.d = function () { return this >= 10 ? this : '0' + this };
        var y = this.y(), m = this.m(), d = this.d(), h = this.h(), i = this.i(), s = this.s();
        var mm = m.d(), dd = d.d(), hh = h.d(), ii = i.d(), ss = s.d();
        return f.r('mm', mm).r('dd', dd).r('hh', hh).r('ii', ii).r('ss', ss).r('m', m).r('d', d).r('h', h).r('i', i).r('s', s).r('yyyy', y);
    };
    Date.sameYear = function (d1, d2) { return d1.y() == d2.y(); };
    Date.sameMonth = function (d1, d2) { return Date.sameYear(d1, d2) && d1.m() == d2.m(); };
    Date.sameDay = function (d1, d2) { return Date.sameMonth(d1, d2) && d1.d() == d2.d(); };
    Date.sameHour = function (d1, d2) { return Date.sameDay(d1, d2) && d1.h() == d2.h(); };
    Date.sameMinute = function (d1, d2) { return Date.sameHour(d1, d2) && d1.i() == d2.i(); };

    function make(t, p, a, s, c) {
        var e = $d.createElement(t);
        if (a) { for (var i in a) e.setAttribute(i, a[i]); }
        if (s) { for (var i in s) e.style[i] = s[i]; }
        if (navigator && navigator.userAgent) {
            var g = navigator.userAgent;
            if (g.indexOf('MSIE 6.0') > 0 || g.indexOf('MSIE 7.0') > 0)
                e = $d.createElement(e.outerHTML.replace('\r\n', ''));
        }
        if (c) e.innerHTML = c;
        if (p) p.appendChild(e);
        return e;
    }
    function stopProp(e) {
        if (e.stopPropagation) e.stopPropagation();
        else e.cancelBubble = true;
    }
    function addEvent(o, e, f) {
        if (o.addEventListener) o.addEventListener(e, f);
        else if (o.attachEvent) o.attachEvent('on' + e, f);
    }
    function decade(d) {
        var y = d.y(); var i = y % 10; var b = y - i; var e = b + 9;
        return [b, e];
    }
    function look() { return new Date(window.event.srcElement.getAttribute('date')); }
    var that = this;
    var ctrl, head, grid, prev, next, title, input;
    var state = 2, d = new Date(), x = 0, y = 0, on = false, ts = false, df = 'yyyy/mm/dd', dtf = 'yyyy/mm/dd hh:ii:ss';
    var hide = function () {
        $d.body.removeChild(ctrl);
        on = false;
    }
    var pick = function () {
        if (input) input.value = ts ? d.fs(dtf) : d.fs(df);
        hide();
    }
    var goPrev = function () {
        switch (state) {
            case 0: d.setYear(d.y() - 10); break;
            case 1: d.setYear(d.y() - 1); break;
            case 2: d.setMonth(d.n() - 1); break;
            case 3: d.setDate(d.d() - 1); break;
            case 4: d.setHours(d.h() - 1); break;
        }
        view();
        return false;
    }
    var goNext = function () {
        switch (state) {
            case 0: d.setYear(d.y() + 10); break;
            case 1: d.setYear(d.y() + 1); break;
            case 2: d.setMonth(d.n() + 1); break;
            case 3: d.setDate(d.d() + 1); break;
            case 4: d.setHours(d.h() + 1); break;
        }
        view();
        return false;
    }
    var goBack = function () {
        if (state > 0) { state--; view(); }
        return false;
    }
    var goDeep = function () {
        d = look();
        switch (state) {
            case 0:
            case 1:
            case 3: state++; view(); break;
            case 2: if (ts) { state++; view(); } else pick(); break;
            case 4: pick(); break;
        }
        return false;
    }
    var makeGrid = function () {
        var g = make('table', ctrl, { 'class': 'grid' });
        var t = new Date(), p = new Date(d), css = '', a = false, b = false;
        switch (state) {
            case 0:
                var de = decade(p);
                p.setFullYear(de[0] - 1);
                for (var r = 0; r < 3; r++) {
                    var tr = make('tr', g);
                    for (var c = 0; c < 4; c++) {
                        var y = p.y(); css = ''; a = Date.sameYear(p, t); b = Date.sameYear(p, d);
                        if (a && b) css = 'pl'; else if (a) css = 'hl'; else if (b) css = 'sl'; else if (y < de[0] || y > de[1]) css = 'gl';
                        var td = make('td', tr, { 'class': css, 'date': p.fs('yyyy/mm/dd') }, { 'width': '25%' }, p.y());
                        td.onclick = goDeep;
                        p.setFullYear(y + 1);
                    }
                }
                break;
            case 1:
                var m = $sc.months, i = 0;
                p = new Date(d.y(), 0, 1);
                for (var r = 0; r < 3; r++) {
                    var tr = make('tr', g);
                    for (var c = 0; c < 4; c++, i++) {
                        p.setMonth(i); css = ''; a = Date.sameMonth(p, t); b = Date.sameMonth(p, d);
                        if (a && b) css = 'pl'; else if (a) css = 'hl'; else if (b) css = 'sl';
                        var td = make('td', tr, { 'class': css, 'date': p.fs('yyyy/mm/dd') }, { 'width': '25%' }, m[i]);
                        td.onclick = goDeep;
                    }
                }
                break;
            case 2:
                p = new Date(d.y(), d.n(), 1);
                var b = p.getDay();
                p.setDate((b == 0 ? p.d() - 7 : p.d() - b));
                var h = make('tr', g);
                for (var c = 0; c < 7; c++)
                    var th = make('th', h, null, null, $sc.weeks[c]);
                for (var r = 0; r < 6; r++) {
                    var tr = make('tr', g);
                    for (var c = 0; c < 7; c++) {
                        css = ''; a = Date.sameDay(p, t); b = Date.sameDay(p, d);
                        if (a && b) css = 'pl'; else if (a) css = 'hl'; else if (b) css = 'sl'; else if (!Date.sameMonth(p, d)) css = 'gl';
                        var td = make('td', tr, { 'class': css, 'date': p.fs('yyyy/mm/dd') }, { 'width': '14%' }, p.d());
                        td.onclick = goDeep;
                        p.setDate(p.d() + 1);
                    }
                }
                break;
            case 3:
                var i = 0;
                for (var r = 0; r < 4; r++) {
                    var tr = make('tr', g);
                    for (var c = 0; c < 6; c++, i++) {
                        p.setHours(i); css = '';
                        if (Date.sameHour(p, t)) css = 'hl'; else if (Date.sameHour(p, d)) css = 'sl';
                        var td = make('td', tr, { 'class': css, 'date': p.fs('yyyy/mm/dd hh:ii:ss') }, { 'width': '16.7%' }, i.toString());
                        td.onclick = goDeep;
                    }
                }
                break;
            case 4:
                var i = 0;
                for (var r = 0; r < 6; r++) {
                    var tr = make('tr', g);
                    for (var c = 0; c < 10; c++, i++) {
                        p.setMinutes(i); css = '';
                        if (Date.sameMinute(p, t)) css = 'hl'; else if (Date.sameMinute(p, d)) css = 'sl';
                        var td = make('td', tr, { 'class': css, 'date': p.fs('yyyy/mm/dd hh:ii:ss') }, { 'width': '10%' }, i + '\'');
                        td.onclick = goDeep;
                    }
                }
                break;
        }
        return g;
    }
    var view = function () {
        if (grid) ctrl.removeChild(grid);
        if (on) $d.body.removeChild(ctrl);
        grid = makeGrid();
        var t = '';
        switch (state) {
            case 0: var de = decade(d); t = de[0] + '-' + de[1]; break;
            case 1: t = d.fs('yyyy'); break;
            case 2: t = d.fs('yyyy-mm'); break;
            case 3: t = d.fs('yyyy-mm-dd'); break;
            case 4: t = d.fs('yyyy-mm-dd hh'); break;
        }
        title.innerHTML = t;
        ctrl.style.left = x + 'px'; ctrl.style.top = y + 'px';
        $d.body.appendChild(ctrl);
        on = true;
    }
    this.show = function (id, ets) {
        if (on) hide();
        else {
            var e = $d.getElementById(id);
            if (e) {
                y = e.offsetTop + e.offsetHeight;
                x = e.offsetLeft;
                var t = new Date(e.value);
                if (isNaN(t)) t = new Date();
                d = t;
                input = e;
                ts = ets;
                state = 2;
                view();
            }
        }
    }
    ctrl = make('div', null, { 'class': 'smithcalendar' });
    head = make('div', ctrl, { 'class': 'head' });
    prev = make('a', head, { 'class': 'prev' }); prev.onclick = goPrev;
    next = make('a', head, { 'class': 'next' }); next.onclick = goNext;
    var p = make('div', head, { 'class': 'title' });
    title = make('a', p); title.onclick = goBack;
    ctrl.onclick = function () { stopProp(event); }
    addEvent($d, 'click', function () { hide(); });
    return {
        show: function (id, options) { stopProp(event); that.show(id, options); }
    };
}
$sc.months = ['Jan', 'Feb', 'Mar', 'Apr', 'Mar', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
$sc.weeks = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
$sc.show = function (id, options) {
    if (!$sc.instance) $sc.instance = new $sc();
    $sc.instance.show(id, options);
}
SmithCalendar = $sc;